﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ZooKeeperNet;

namespace DistributedLock
{
    public class ZKServer : IDisposable
    {
        public ZKServer()
        {

        }

        /// <summary>
        /// 创建带有并发数量的实例
        /// </summary>
        /// <param name="limit">并发数量</param>
        public ZKServer(int limit)
        {
            if (limit <= 0)
            {
                throw new Exception("limit must be greater then zero");
            }
            this.Limit = limit;
        }

        public int Limit { get; set; }

        /// <summary>
        /// 排它锁
        /// </summary>
        public ExclusiveLock ExclusiveLock
        {
            get
            {
                return new ExclusiveLock(this);
            }
        }

        /// <summary>
        /// 当前线程的唯一Id
        /// </summary>
        public string UniqueThreadId
        {
            get
            {
                return Environment.MachineName + "_" + Process.GetCurrentProcess().ProcessName + "_" + Thread.CurrentThread.ManagedThreadId;
            }
        }

        /// <summary>
        /// 创建持久性节点
        /// 节点值为DateTime.Now.Ticks
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public string CreateNode(string node)
        {
            try
            {
                var bytes = Encoding.UTF8.GetBytes(DateTime.Now.Ticks.ToString());
                return ZKClient.Client.Create(node, bytes, Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 创建节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="nodeValue"></param>
        /// <param name="createMode"></param>
        /// <returns></returns>
        public string CreateNode(string node, string nodeValue, CreateMode createMode)
        {
            try
            {
                var bytes = Encoding.UTF8.GetBytes(nodeValue);
                return ZKClient.Client.Create(node, bytes, Ids.OPEN_ACL_UNSAFE, createMode);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 创建分布式锁节点
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public string CreateMetexNode(string node)
        {
            try
            {
                //存在并发控制
                if (this.Limit > 0)
                {
                    if (!this.ExclusiveLock.CanContinue(node))
                    {
                        return null;
                    }
                }

                var bytes = Encoding.UTF8.GetBytes(this.UniqueThreadId);
                return ZKClient.Client.Create(node, bytes, Ids.OPEN_ACL_UNSAFE, CreateMode.EphemeralSequential);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static bool CreateNodeTree(string nodePath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(nodePath))
                {
                    throw new Exception("nodePath is null or whitespace");
                }

                if (!nodePath.StartsWith("/"))
                {
                    throw new Exception("nodePath must be started with character \"/\"");
                }

                ZooKeeperNet.ZKPaths.Mkdirs(ZKClient.Client, nodePath);

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="node"></param>
        public static void DeleteNode(string node)
        {
            try
            {
                if (ZKClient.Client.Exists(node, false) != null)
                {
                    ZKClient.Client.Delete(node, -1);
                }
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
            }
        }

        /// <summary>
        /// 删除子节点
        /// </summary>
        /// <param name="node"></param>
        public static void DeleteChildNode(string parentNode)
        {
            var children = ZKUtility.GetChildren(parentNode);
            foreach (var node in children)
            {
                try
                {
                    var path = parentNode.Combine(node);
                    if (ZKClient.Client.Exists(path, false) != null)
                    {
                        ZKClient.Client.Delete(path, -1);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }
    }
}
